package com.qihetimes.earthangel.service.impl;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.jiguang.common.ClientConfig;
import cn.jiguang.common.ServiceHelper;
import cn.jiguang.common.connection.NativeHttpClient;
import cn.jiguang.common.resp.APIConnectionException;
import cn.jiguang.common.resp.APIRequestException;
import cn.jpush.api.JPushClient;
import cn.jpush.api.push.PushResult;
import cn.jpush.api.push.model.Options;
import cn.jpush.api.push.model.Platform;
import cn.jpush.api.push.model.PushPayload;
import cn.jpush.api.push.model.audience.Audience;
import cn.jpush.api.push.model.notification.AndroidNotification;
import cn.jpush.api.push.model.notification.IosNotification;
import cn.jpush.api.push.model.notification.Notification;
import com.qihetimes.earthangel.common.MessageType;
import com.qihetimes.earthangel.config.JPushConfig;
import com.qihetimes.earthangel.model.Conversation;
import com.qihetimes.earthangel.model.ConversationMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;

/**
 * 极光推送服务类
 *
 * @author ：f4cklangzi@gmail.com
 * @date ：Created At 2022/1/3
 */
@Slf4j
@Service
public class JPushClientService {
    
    @Resource
    private JPushConfig jPushConfig;
    
    @Resource
    private ThreadPoolTaskExecutor taskExecutor;
    
    /**
     * 构建推送平台
     *
     * @param platform 指定推送平台
     * @return Platform
     */
    private static Platform buildPlatform(String platform) {
        switch (platform) {
            case JPushConfig.PLATFORM_ALL:
                return Platform.all();
            case JPushConfig.PLATFORM_ANDROID:
                return Platform.android();
            case JPushConfig.PLATFORM_IOS:
                return Platform.ios();
            case JPushConfig.PLATFORM_WINPHONE:
                return Platform.winphone();
            case JPushConfig.PLATFORM_ANDROID_IOS:
                return Platform.android_ios();
            case JPushConfig.PLATFORM_ANDROID_WINPHONE:
                return Platform.android_winphone();
            case JPushConfig.PLATFORM_IOS_WINPHONE:
                return Platform.ios_winphone();
            default:
        }
        return Platform.all();
    }
    
    /**
     * 构建推送目标
     *
     * @param audience       指定推送范围
     * @param audienceValues 指定推送目标
     * @return Audience
     */
    private static Audience buildAudience(String audience, List<String> audienceValues) {
        switch (audience) {
            case JPushConfig.AUDIENCE_ALL:
                return Audience.all();
            case JPushConfig.AUDIENCE_TAG:
                return Audience.tag(audienceValues);
            case JPushConfig.AUDIENCE_TAG_AND:
                return Audience.tag_and(audienceValues);
            case JPushConfig.AUDIENCE_TAG_NOT:
                return Audience.tag_not(audienceValues);
            case JPushConfig.AUDIENCE_ALIAS:
                return Audience.alias(audienceValues);
            case JPushConfig.AUDIENCE_REGISTRATION_ID:
                return Audience.registrationId(audienceValues);
            case JPushConfig.AUDIENCE_SEGMENT:
                return Audience.segment(audienceValues);
            case JPushConfig.AUDIENCE_ABTEST:
                return Audience.abTest(audienceValues);
            default:
        }
        return Audience.all();
    }
    
    /**
     * 构建通知内容体
     *
     * @param title   通知标题
     * @param message 通知内容
     * @param extras  扩展字段
     * @return Notification
     */
    private static Notification buildNotification(String title, String message, String extras) {
        Notification.Builder notification = Notification.newBuilder()
            .setAlert(message)
            .addPlatformNotification(AndroidNotification.newBuilder().setTitle(title).setBuilderId(2).addExtra(
                "extras", extras).build())
            .addPlatformNotification(IosNotification.newBuilder().incrBadge(1).addExtra("extras", extras).build());
        // 构建iOS平台上的通知结构
        return notification.build();
    }
    
    /**
     * 推送push消息
     *
     * @param platform       指定推送平台
     * @param audience       指定推送范围
     * @param audienceValues 指定推送目标
     * @param title          通知标题
     * @param message        通知内容
     * @param extras         扩展字段
     */
    public void sendPush(String platform, String audience, List<String> audienceValues, String title, String message,
        String extras) {
        // 构建推送对象
        PushPayload payload = buildPushPayload(platform, audience, audienceValues, title, message, extras);
        // 推送push消息
        sendPush(payload);
    }
    
    /**
     * 对单个用户进行推送
     *
     * @param registrationId 用户注册ID
     * @param conversation   会话
     * @param message        消息
     */
    public void sendPush(String registrationId, Conversation conversation, ConversationMessage message) {
        String title = conversation.getFromUserNickName();
        String messageStr = "";
        JSONObject extraJson = new JSONObject();
        extraJson.set("conversationId", conversation.getId());
        extraJson.set("messageId", message.getId());
        extraJson.set("messageType", message.getMessageType());
        extraJson.set("content", message.getContent());
        String extras = JSONUtil.toJsonStr(extraJson);
        MessageType messageType = MessageType.valueOf(message.getMessageType());
        switch (messageType) {
            case TEXT:
                messageStr = message.getContent();
                break;
            case IMAGE:
                messageStr = "[图片]";
                break;
            case FRIEND_ADD:
                String userName = JSONUtil.parseObj(message.getContent()).getStr("nickName");
                messageStr = userName + " 添加你为好友";
                break;
            case GOODS_REVIEW_REJECT:
                String name = JSONUtil.parseObj(message.getContent()).getStr("name");
                messageStr = "你的物品[" + name + "]审核未通过!";
                break;
            case INTEGRAL_CHANGE:
                JSONObject content = JSONUtil.parseObj(message.getContent());
                Integer newIntegral = content.getInt("newIntegral");
                Integer oldIntegral = content.getInt("oldIntegral");
                Integer oldLevel = content.getInt("oldLevel");
                Integer newLevel = content.getInt("newLevel");
                int changeCount = newIntegral - oldIntegral;
                messageStr = "恭喜你获得积分:" + changeCount;
                if (!newLevel.equals(oldLevel)) {
                    messageStr += ",等级提升为Lv" + newLevel;
                }
                break;
            default:
        }
        List<String> registrationIdList = Collections.singletonList(registrationId);
        // 构建推送对象
        PushPayload payload = buildPushPayload(JPushConfig.PLATFORM_ALL, JPushConfig.AUDIENCE_REGISTRATION_ID,
            registrationIdList, title, messageStr, extras);
        // 推送push消息
        sendPush(payload);
    }
    
    /**
     * 推送push消息
     *
     * @param payload 推送对象
     */
    public void sendPush(PushPayload payload) {
        ClientConfig clientConfig = ClientConfig.getInstance();
        ClientConfig.getInstance().setPushHostName("https://bjapi.push.jiguang.cn");
        
        String authCode = ServiceHelper.getBasicAuthorization(jPushConfig.getAppKey(), jPushConfig.getMasterSecret());
        
        NativeHttpClient httpClient = new NativeHttpClient(authCode, null, clientConfig);
        
        JPushClient jpushClient = new JPushClient(jPushConfig.getMasterSecret(), jPushConfig.getAppKey(), null,
            clientConfig);
        jpushClient.getPushClient().setHttpClient(httpClient);
        taskExecutor.execute(() -> {
            try {
                PushResult res = jpushClient.sendPush(payload);
                if (!res.isResultOK()) {
                    log.info("推送失败，PushResult：{}", res);
                }
            } catch (APIConnectionException e) {
                log.error("Connection error. Should retry later. ", e);
                log.error("Sendno: " + payload.getSendno());
            } catch (APIRequestException e) {
                log.error("Error response from JPush server. Should review and fix it. ", e);
                log.info("HTTP Status: " + e.getStatus());
                log.info("Error Code: " + e.getErrorCode());
                log.info("Error Message: " + e.getErrorMessage());
                log.info("Msg ID: " + e.getMsgId());
                log.error("Sendno: " + payload.getSendno());
            }
        });
    }
    
    /**
     * 构建推送对象
     *
     * @param platform       指定推送平台
     * @param audience       指定推送范围
     * @param audienceValues 指定推送目标
     * @param title          通知标题
     * @param message        通知内容
     * @param extras         扩展字段
     * @return PushPayload
     */
    public PushPayload buildPushPayload(String platform, String audience, List<String> audienceValues, String title,
        String message, String extras) {
        Options option = Options.newBuilder().setApnsProduction(true).setTimeToLive(86400).build();
        return PushPayload.newBuilder()
            .setPlatform(buildPlatform(platform))
            .setAudience(buildAudience(audience, audienceValues))
            .setNotification(buildNotification(title, message, extras))
            .setOptions(option)
            .build();
    }
}
